#This file builds VMs based on differencing disks

#versionvarible
$myver="1.2"

#initialize defaults
$ParentDef = "w2k8r2datacenterbase"
$Namedef = "Scratch"
$Networkdef = "ScratchNet"
$Procdef = 2
$ParentDir = "v:\ParentDrives"
$global:VHD="v:\VirtualDisks\"
$procval=1,2,4
$global:VHDType

#memory variables

[int64]$Memdef = 1024MB  #For static 
[int64]$maxmem=4192MB
[int64]$minmem=512MB
[int64]$startupmem=1024MB
[int32]$ReservePercent=20

#mdghost creates a differencing disk
#with the parameters [parentdrive name] [vhdname] [network] [memory] [processors]
#mdghost is parameter validation and main()

function global:New-Ghost
{
param(
    [string]$parent=$ParentDef,
	[string]$newvhd=$Namedef,
	[string]$net=$Networkdef,
	[int]$cpu=$ProcDef,
	[switch]$help,
	[switch]$go,
    [switch]$dyn,
    [switch]$off,
    [int64]$mem=$memdef,
    [int32]$res=$ReservePercent,
    [int64]$min=$minmem,
    [int64]$start=$startupmem,
    [int64]$max=$maxmem)

if ($help)
	{
        write-host "Version:"$myver
		write-host "NAME:"
        write-host "NEW-GHOST"
        write-host "New-Ghost [-newvhd] <VHDNAME> [-parent] <PARENTNAME> [-net] NetworkName [-cpu] <CPUCount> [-mem] <MAXMemory in MB> [-dyn] <UseDynamicMemoryParamters> [-res] <reserve percentage [-min] <Minimum Memory in MB> [-start] <Startup Memory in MB> [-max] <Maximum Memory in MB> [-go] <No Prompts [-off] <Do Not Turn ON after creating>"
        write-host "`nCurrent Defaults:"
        write-host "`t-parent:`t$parentdef"
        write-host "`t-newvhd`t$NameDef"
        write-host "`t-net:`t$NetworkDef"
        write-host "`t-cpu:`t$procdef"
        write-host "`t-mem:`t"($memdef/1024/1024)
        write-host "`nDynamic Memory Defaults:"
        write-host "`t-res:`t$ReservePercent"
        write-host "`t-min:`t"($minmem/1024/1024)
        write-host "`t-start:`t"($startupmem/1024/1024)
        write-host "`t-max:`t"($maxmem/1024/1024)
 		return
	}

#find the parent vhd
$ptemp = Choose-ParentVHD $parent

if (($ptemp -match "vhd$") -or ($ptemp -match "vhdx")) 
    {
	$vParent=$ptemp
	write-debug "Validated Parent $vParent"
    $global:VHDType=$matches.values
    
    }
	else
	{
		write-error "Parent $parent not Found." -errorid Hyperwrap_NoParent
		return
	}		


#validate the vhd name and/or create a new one
if ($newvhd -like $NameDef)
	{
		#create a randomvhd name
		$testpath=GenRandomVHD
		while (test-path "$vhd\$testpath.$vhdtype")
		{
			$testpath=GenRandomVHD
		}
		$vNewVHD="$testpath.$vhdtype"
		$NewVHD=$TestPath
	}
elseif ((test-path "$vhd$newvhd.$vhdType"))
	{
		write-error "$newvhd already exists" -errorid HyperWrap_VHDAlreadyExists
		return
	}
else
	{
		$vNewVHD="$NewVHD.$VhdType"
	}

write-debug "NewVHD is $vNewVHD.$vhdtype"

#validate the netname
$vnet=Get-VmSwitch | ? {$_.Name -eq $net}

If ($vnet.count -ne 1)
{
    $vNet = Choose-VMSwitch $net
}

if ($vNet)
	{
		write-debug "Valid NetName $($vnet.name)"
	}
	else
	{
		write-error "Network $net does not exist" -errorid HyperWrap_NoNet
		return
	}
#need to add code to check dynamic memory parameters

#Validate reserve values
if (($res -lt 1) -or ($res -gt 100))
    {write-error "Reserve Out of Bounds: $res" -errorid HyperWrap_ReserveOutofBounds
    return
    }

#validate memory problems

If (($max -lt $min) -or ($max -lt $start) -or ($min -gt $start))
    {
        write-error "Memory Values Invalid"
        write-error "Min: $min"
        write-error "Max: $max"
        Write-error "Start: $start"
        write-error "Invalid Memory Parameter" -errorid HyperWrap_InvalidMemoryParameter
        return
        }	
if (($mem -gt $maxmem) -or ($mem -lt $minmem))
	{
		write-Error "Memory Out of Bounds: $mem" -errorid HyperWrap_MemoryOut of Bounds
		return
	}

if ($procval -notcontains $cpu)
	{
		write-error "Invalid CPU parameter $cpu" -errorid HyperWrap_InvalidCPuNum
		return
	}

#theoretically, we've validated all the parameters
#time to create the VHD

if (-not $go)
	{
		write-host "`n`nParent:$vparent`tVHD:$newvhd`tNet:$($vnet.name)`tMemory:$($mem/$([MATH]::Pow(1024,2)))MB`tCPU:$cpu"
		$c=read-host "Confirm (y/n)"
		if ($c -ne "y") {return}
	}

write-debug "New-Vhd $vhd$Vnewvhd -parent $ParentDir\$vParent"
write-host "`n`n"

#create the vhd
$myvhd=new-vhd -path "$vhd$Vnewvhd" -parentpath "$ParentDir\$vParent" -differencing


#create the nm
write-debug "New-VM $newvhd"
$MyVm=New-VM -name $newvhd  -MemoryStartupBytes $mem -switchname $vnet.Name -vhdpath $myvhd.Path 

#Set the CPUCount
Set-VMProcessor $myvm.VMName -count $cpu

#if dynamic memory is specified use dynamic memory defaults

if ($dyn)
    {
	
	    Set-VMMemory $myvm -DynamicMemoryEnabled $TRUE -buffer $res -MaximumBytes $max -StartupBytes $start -MinimumBytes $min		
	}
    else
    {
        Set-VMMemory $myvm -DynamicMemoryEnabled $TRUE -buffer $res -MaximumBytes $mem -StartupBytes $mem -MinimumBytes $min
    }

#Start the VM
start-vm $myvm.vmname



} #end of mdghost
		
function script:GenRandomVHD
{
	#Append a Random Value to the name of the vhd
	$random=new-object random
	$append=$random.next(268435456,536870912)
	$hexval="{0:X}" -f $append
	$append=$hexval.TOString()
	$full="$NameDef-$append"
	return $full
}

	
Function Choose-List
{Param ($InputObject, $Property, [Switch]$multiple)
 $Global:counter=-1
 $Property=@(@{Label="ID"; Expression={ ($global:Counter++) }}) + $Property
 if ($inputObject -is [Array]) {
     $InputObject | format-table -autosize -property $Property | out-host
     if ($multiple) { $InputObject[ [int[]](Read-Host "Which one(s) ?").Split(",")] }
     else           { $InputObject[        (Read-Host "Which one ?")              ] }}
 else {$inputObject}
}

Function Choose-VMSwitch
{Param($net)
 choose-list  (Get-VMSwitch | ? {$_.name -like "*$($net)*"}) @(@{Label="Switch Name"; Expression={$_.Name}} )
}

Function Choose-ParentVHD
{Param ($parent)
 choose-list (get-childitem $parentdir |? {$_.name -like "*$parent*.vhd*"}) @(@{Label="Parent VHD";Expression={$_}})
 }
